//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-06-06     ZhangYihua   first version
//
// Description  : convert binary number to gray code number
//################################################################################

module bin2gray #(
parameter           BW                      = 8,            // bit width
parameter           REG_EN                  = 1'b1,         // generally, gray must be REGed before synchronization to different clock domain
parameter           GRY_INI                 = {BW{1'b0}}    // initial value must be a gray code too
) ( 
input                                       rst_n,
input                                       clk,

input               [BW-1:0]                i_bin,          // binary
output              [BW-1:0]                o_gray          // gray
);

//################################################################################
// define local varialbe and localparam
//################################################################################
wire                [BW-1:0]                gray_c;

//################################################################################
// main
//################################################################################

assign gray_c = i_bin ^ (i_bin>>1);

generate if (REG_EN==1'b1) begin:G_REG
    
    reg                 [BW-1:0]                gray_d;

    always@(posedge clk or negedge rst_n) begin
        if (rst_n==1'b0) begin
            gray_d <=`U_DLY GRY_INI;
        end else begin
            gray_d <=`U_DLY gray_c;
        end
    end

    assign o_gray = gray_d;

end else begin:G_NREG

    assign o_gray = gray_c;

end endgenerate

`ifdef CBB_ASSERT_ON
// synopsys translate_off

reg     GRAY_CHKEN;

a_gray: assert property (@(posedge clk) disable iff (!rst_n)
    ((GRAY_CHKEN!==1'b0)&(~$stable(o_gray)) |-> $onehot($past(o_gray)^o_gray))
) else begin
    $error("last gray %b -> cur gray %b is wrong.", $past(o_gray), o_gray);
end

// synopsys translate_on
`endif

endmodule
